/***********************************************************************************
 * 文件名： boost_controller.c
 * 作者： 刘言
 * 版本： 8
 * 说明：
 *      升压控制器（静态、单例），升压电路的驱动，通过电压值反馈调整PWM占空比达到升压，并
 * 恒定电压的目的。
 *      提供以下功能：
 *          升压输出；
 *          电压调节；
 *          过流保护和通知；
 *          过载通知；
 *          开路保护和通知【未实现】。
 * 修改记录：
 * 	2020/11/04: 初版。 刘言。
 *  2021/07/07: V2。支持通过 _BSTC_FULL_ADV 来决定AD值变量类型，尽量降低RAM占用。
 *          增加 _BSTC_USE_ADV_FILTER 开关。
 *          增加 BSTC_EV_OVER_LOAD 事件。
 *          支持 POLSYS_LITE。
 *  2021/07/11: V3.增加配置项“判断过载时允许的向下偏差电压”。
 *  2021/07/12：V4.增加 BSTC_EV_NO_BOOST 事件，现在支持同时发送多个事件，每个事件占据一个位，
 *          见 boostc_event_t ，注意更改判断事件的逻辑。
 *  2021/07/14: V5. BSTC_EV_OVER_LOAD BSTC_EV_NO_BOOST 事件现在可裁剪去掉。
 *  2022/06/22: V6. 引入PID算法加强电压稳定性。仅保留中断中的快速电压调整。启动时输入初始PWM。
 *  2022/07/18: V7. 获取实际电压更准确（9次中值滤波）。
 *  2022/07/21: 始终启用PID；去掉启动函数的电压参数；调整API名称；去掉多余需要设置的API。
***********************************************************************************/
#include "boost_controller.h"
#include "components\pid_static\pid_static.h"
#include "polsys.h"

// 参数计算
#ifdef _BSTC_USE_OVER_LOAD_EVENT
#define BSTC_OL_ALLOW_ADV       (bstc_adv_t)((float)_BSTC_OL_ALLOW_VOLATGE * _BSTC_FBRL / (_BSTC_FBRH + _BSTC_FBRL) * _BSTC_FULL_ADV / _BSTC_ADC_VREF)
#endif
#define BSTC_DEFAULT_ADV        (bstc_adv_t)((float)_BSTC_MAX_OUTPUT_VOLTAGE * _BSTC_FBRL / (_BSTC_FBRH + _BSTC_FBRL) * _BSTC_FULL_ADV / _BSTC_ADC_VREF)

static pdata bstc_adv_t mTargetADV = BSTC_DEFAULT_ADV;        // 要维持的输出电压的目标AD值
#ifdef _BSTC_USE_GET_REAL_VOLTAGE
static pdata bstc_adv_t mFBVBuff[9];
static u8 mFBVBuffIndex = 0;
#endif
static pdata bstc_pwmv_t mPwmValue = 0;    // 当前PWM值
bstc_pwmv_t _BSTC_mMaxPwmValue  = _BSTC_PWM_MAX_VALUE;
bit _BSTC_mRun = false;
static pdata boostc_event_t mEvent = BSTC_EV_NULL;
static pdata u8 mOverCurrentCount = 0;   // 检测到MOS过流的次数
#ifdef _BSTC_USE_OVER_LOAD_EVENT
static pdata u8 mOverLoadCount=0;       // 检测到过载的次数
#endif
#ifdef _BSTC_USE_NO_BOOST_EVENT
static pdata u8 mNoBoostTime=0;         // 未升压计时
#endif


#ifndef POLSYS_LITE
static pdata polsys_task_t mTask;
static void Loop();
#endif

#ifdef _BSTC_USE_STARTED_EVENT
static bit mStarted = false;
#endif

// 声明事件回调函数，（此种方式意味着使用者必须要实现回调函数）
void BSTC_Event(boostc_event_t e);


// 由外部调用（一般是ADC中断）来通知 BSTC 采集到了新的输出电压反馈脚的AD值。
// 建议AD采集间隔40~100us，在采集完成中断中调用。
void BSTC_EvNewFBV(bstc_adv_t adv)
{
    if(_BSTC_mRun)
    {
#ifdef _BSTC_USE_GET_REAL_VOLTAGE
        mFBVBuff[mFBVBuffIndex++] = adv;
        if(mFBVBuffIndex >= 9)
        {
            mFBVBuffIndex = 0;
        }
#endif
#ifdef _BSTC_USE_STARTED_EVENT
        if(mStarted == false)
        {
            mStarted = true;
            BSTC_Event(BSTC_EV_STARTED);
        }
#endif
#ifdef _BSTC_USE_OVER_LOAD_EVENT
        if(adv < BSTC_OL_ALLOW_ADV)    // 电压过低
        {
            if(mOverLoadCount < 255)mOverLoadCount++;
            if(mOverLoadCount == _BSTC_OL_ALLOW_COUNT)
            {
                _BSTC_PwmStop();
                _BSTC_mRun = false;
                mEvent |= BSTC_EV_OVER_LOAD;
            }
        }
        else
        {
            mOverLoadCount = 0;
        }
#endif
        {
            s16 target_pwm = (s16)PID_GetChange(mTargetADV, adv) + mPwmValue;
            if(target_pwm < 0) mPwmValue = 0;
            else if(target_pwm > _BSTC_mMaxPwmValue)mPwmValue = _BSTC_mMaxPwmValue;
            else mPwmValue = target_pwm;
            _BSTC_SetPwm(mPwmValue);
        }
    }
}

void BSTC_EvOverCurrent()
{
    if(mOverCurrentCount >= _BSTC_OC_ALLOW_COUNT)
    {
        BSTC_Stop();
        mEvent |= BSTC_EV_SHORT_OUT;
    }
    mOverCurrentCount++;
}

FORCE_IN_LINE void BSTC_Init()
{
    _BSTC_InitPwm();
    _BSTC_InitAdc();
#ifndef POLSYS_LITE
    Polsys_TaskInit(&mTask,Loop,10);
#endif
}

void BSTC_Start(bstc_pwmv_t start_pwm)
{
    PID_Init();
    mOverCurrentCount = 0;
#ifdef _BSTC_USE_OVER_LOAD_EVENT
    mOverLoadCount = 0;
#endif
    mPwmValue = start_pwm;
#ifdef _BSTC_USE_NO_BOOST_EVENT
    mNoBoostTime = 0;
#endif
#ifdef _BSTC_USE_ADV_FILTER
    mFBVBuffIndex = 0;
    mFBVBuffFull = false;
#endif
    _BSTC_mRun = true;
    mEvent = BSTC_EV_NULL;
    _BSTC_SetPwm(mPwmValue);
    _BSTC_RunAdc();
}

// 停止升压，开关立即截止
IN_LINE void BSTC_Stop()
{
    _BSTC_SetPwm(0);
    _BSTC_StopAdc();
    _BSTC_mRun = false;
#ifdef _BSTC_USE_STARTED_EVENT
    mStarted = false;
#endif
}

void BSTC_SetTarget(u16 voltage)
{
    if(voltage > _BSTC_MAX_OUTPUT_VOLTAGE)voltage = _BSTC_MAX_OUTPUT_VOLTAGE;
    mTargetADV = ((u32)voltage*_BSTC_FBRL*_BSTC_FULL_ADV)/((u32)(_BSTC_FBRH + _BSTC_FBRL)*_BSTC_ADC_VREF);
}

#ifdef _BSTC_USE_GET_REAL_VOLTAGE
// 获取当前实际输出电压，启动1ms之后才能获取准确的值，单位mV
u16 BSTC_GetNowVoltage()
{
    u16 v;
    //v = mNowADV * (u32)((float)_BSTC_ADC_VREF * (_BSTC_FBRH + _BSTC_FBRL) / _BSTC_FULL_ADV  / _BSTC_FBRL * 1000) / 1000;
    #if (_BSTC_FULL_ADV > 256)
        v = MedianFilter16b9(mFBVBuff) * (u32)_BSTC_ADC_VREF * (_BSTC_FBRH + _BSTC_FBRL) / _BSTC_FULL_ADV  / _BSTC_FBRL;
    #else
        v = MedianFilter8b9(mFBVBuff) * (u32)_BSTC_ADC_VREF * (_BSTC_FBRH + _BSTC_FBRL) / _BSTC_FULL_ADV  / _BSTC_FBRL;
    #endif
    return v;
}
#endif

// 以下是内部函数

#ifdef POLSYS_LITE
// 建议间隔10ms运行一次
void BSTC_Loop()
#else
// 循环处理的任务，间隔10ms会被调用一次
static void Loop()
#endif
{
    if(_BSTC_mRun)
    {
        
#ifdef _BSTC_USE_NO_BOOST_EVENT
            if(mPwmValue == 0)  // PWM值为0
            {
                if(mNoBoostTime<255)mNoBoostTime++;
                if(mNoBoostTime == 10)  // 持续100ms
                {
                    mEvent |= BSTC_EV_NO_BOOST;
                }
            }
            else
            {
                mNoBoostTime = 0;
            }
#endif
        mOverCurrentCount = 0;
    }
    if(mEvent != BSTC_EV_NULL)
    {
        BSTC_Event(mEvent); // 调用事件回调，通知异常事件
        mEvent = BSTC_EV_NULL;
    }
}
